/* $Id: UsersModel.java 129 2011-08-26 05:27:43Z altdotua@gmail.com $ */

package alt.djudge.frontend.server.models;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.hibernate.criterion.Order;

import alt.djudge.frontend.server.Deployment;
import alt.djudge.frontend.server.datatypes.SessionEntry;
import alt.djudge.frontend.server.datatypes.UserEntry;


public class UsersModel
{
	private static final Logger log = Logger.getLogger(UsersModel.class);
	
	private static CoreInterface<UserEntry> core = Deployment.isGAE() ?
		
		new AbstractBigtableModelCore<UserEntry>()
		{
			@Override
			protected Order getOrdering()
			{
				return Order.asc("username");
			}
			
			@Override
			protected Class<UserEntry> getEntryClass()
			{
				return UserEntry.class;
			}
		}
	:
		new AbstractDBModelCore<UserEntry>()
		{
			@Override
			protected Order getOrdering()
			{
				return Order.asc("username");
			}
			
			@Override
			protected Class<UserEntry> getEntryClass()
			{
				return UserEntry.class;
			}
		};		
	
	public static List<UserEntry> getAllEntries()
	{
		return core.getAllEntries();
	}
	
	public static Map<Long, UserEntry> getEntriesMap()
	{
		List<UserEntry> list = getAllEntries();
		HashMap<Long, UserEntry> result = new HashMap<Long, UserEntry>();
		for (UserEntry entry: list)
			result.put(entry.getId(), entry);
		return result;
	}
	
	public static List<UserEntry> getEntries(Map<String, Object> map)
	{
		return core.getEntries(map);
	}
	
	
	public static UserEntry getUserByUsername(String username)
	{
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("username", username);
		List<UserEntry> list = core.getEntries(map);
		if (list.size() > 0)
			return list.get(0);
		return null;
	}
	
	public static UserEntry getUserByEmail(String email)
	{
		UserEntry entry = null;
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("email", email);
		List<UserEntry> list = core.getEntries(map);
		if (list.size() > 0)
			entry = list.get(0);
		return entry;
	}
	
	public static UserEntry getUser(Long userId)
	{
		return (UserEntry) core.getEntry(userId);
	}
	
	// TODO: fetch by username, then check password
	public static UserEntry getUser(String username, String password)
	{
		UserEntry entry = null;
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("username", username != null ? username : "");
		List<UserEntry> list = (List<UserEntry>) core.getEntries(map);
		if (list.size() > 0)
			entry = list.get(0);
		return entry != null && entry.getPassword().equals(password) ? entry : null;
	}
	
	public static Long getUserId(String username, String password)
	{
		UserEntry userEntry = getUser(username, password);
		return userEntry.getPassword().equals(password) ? userEntry.getId() : 0;
	}
		
	public static List<UserEntry> getContestUsers(String contestId)
	{
		HashMap<String, Object> map = new HashMap<String, Object>();
		map.put("role", "user");
		return UsersModel.getEntries(map);
//		Vector<UserEntry> res = new Vector<UserEntry>();
		/*List<SubmissionEntry> subm = SubmissionsModel.getSubmissions(map);
		HashSet<Long> userIds = new HashSet<Long>();
		for (SubmissionEntry submission: subm)
			userIds.add(submission.getUserId());
		for (Long string: userIds)
			res.add(UsersModel.getUser(string.toString()));*/
		//return res;
	}

	private static String getPass()
	{
		String chars = "qwertyuiopasdfghjklzxcvbnm1234567890";
		StringBuilder sb = new StringBuilder();
		Random r = new Random();
		for (int i = 0; i < 6; i++)
			sb.append(
					chars.charAt(Math.abs(r.nextInt()) % chars.length()
							));
		return sb.toString();
	}
	
	public static void generatePasswords(String prefix)
	{
		List<UserEntry> users = UsersModel.getAllEntries();
		for (UserEntry user: users)
		{
			System.out.println(user);
			if (user.getRole().equals("user") && user.getUsername().startsWith(prefix))
			{
				user.setPassword(getPass());
				user.makePersistent();
			}
		}
	}

	public static void deleteEntry(Long id)
	{
		core.deleteEntry(id);
	}
	
	/*
	 * Tries to perform login
	 * Returns UserEntry of logged-in user or null if supplied authentification data is invalid
	 */
	public static UserEntry setCurrentUser(HttpServletRequest request, HttpServletResponse response) throws IOException
	{
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		log.debug("Trying to login as " + username + "/" + password + "...");
		
		UserEntry user = UsersModel.getUserByUsername(username);
		// valid username/password
		if (user != null && user.getPassword().equals(password))
		{
			if (user.getLoginAllowed() == null || user.getLoginAllowed())
				return user;
			setCredentials(request, response, user);
			return user;
		}
		return null;
	}
	
	public static void setCredentials(HttpServletRequest request, HttpServletResponse response, UserEntry user)
	{
		request.getSession().setMaxInactiveInterval(10000000);
		SessionEntry authSession = new SessionEntry();
		authSession.setUserId(user.getId());
		authSession.setAuthToken(SessionsModel.generateAuthToken());
		authSession.setIp(request.getRemoteAddr());
		authSession.makePersistent();
		boolean useSession = request.getParameter("sessionLogin") != null && request.getParameter("sessionLogin").length() != 0; 
		RequestStorageModel.saveData("authToken", authSession.getAuthToken(), request, response, useSession);
	}
	
	public static void removeCurrentUser(HttpServletRequest request, HttpServletResponse response)
	{
		RequestStorageModel.deleteData("authToken", request, response);
	}
	
	// returns current user (logged in) or null
	public static UserEntry getCurrentUser(HttpServletRequest request)
	{
		Object authTokenObj = RequestStorageModel.getData("authToken", request);
		if (authTokenObj == null || authTokenObj.toString().length() == 0)
			return null;
		
		String authToken = authTokenObj.toString();
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("authToken", authToken);
		Date now = new Date();
		List<SessionEntry> sessions = SessionsModel.getEntries(params);
		for (SessionEntry sessionEntry : sessions)
			if (sessionEntry.getExpireTime().after(now))
			{
				UserEntry user = UsersModel.getUser(sessionEntry.getUserId());
				if (user != null)
				{
					sessionEntry.setUpdateTime(now);
					sessionEntry.makePersistent();
					return user;
				}
			}
		return null;
	}
	
	public static CoreInterface<UserEntry> getCore()
	{
		return core.getAdapter();
	}
}
